﻿namespace Vibstudio.NetConfigurator.Engine.Composition
{
    #region Namespaces

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Reflection;
    using System.Xml.Linq;

    using Vibstudio.NetConfigurator.Common;
    using Vibstudio.NetConfigurator.Exceptions;
    using Vibstudio.NetConfigurator.Model;

    #endregion

    [Obfuscation(Exclude = true, ApplyToMembers = false)]
    internal class DomainComposer : IComposition
    {
        #region Static Fields

        private static List<string> _compositionCache;

        #endregion

        #region Public Methods and Operators

        public bool Compose(NetConfig netConfig)
        {
            if (_compositionCache == null)
            {
                _compositionCache = new List<string>();
            }

            XDocument referenceFile = XDocument.Load(netConfig.ConfigurationFileReferencePath);
            XDocument configurationsFile = XDocument.Load(ConfigurationHelper.ConfigurationsFilePath);

            try
            {
                bool composed = PerformComposition(referenceFile,
                                                   configurationsFile,
                                                   netConfig.ConfigurationID);
                if (composed)
                {
                    configurationsFile.Save(ConfigurationHelper.ConfigurationsFilePath);
                }

                return composed;
            }
            catch (AutocompositionAlreadyPerformedException)
            {
                return true;
            }
        }

        public void Reset()
        {
            _compositionCache = null;
        }

        #endregion

        #region Methods

        private bool PerformComposition(XDocument referenceFile, XDocument targetFile, string configurationID)
        {
            if (_compositionCache.Contains(configurationID))
            {
                throw new AutocompositionAlreadyPerformedException(configurationID);
            }

            try
            {
                XElement referenceElement =
                    referenceFile
                        .Descendants("authentication")
                        .Where(e =>
                            {
                                XAttribute modeAttribute = e.Attribute("mode");
                                return modeAttribute != null && modeAttribute.Value.ToLower() == "forms";
                            })
                        .Elements("forms")
                        .FirstOrDefault();

                if (referenceElement != null)
                {
                    XAttribute referenceAttribute = referenceElement.Attribute("domain");
                    if (referenceAttribute != null)
                    {
                        IEnumerable<XElement> targetElements =
                            targetFile
                                .Descendants("configuration")
                                .Elements("name")
                                .Where(e => (string)e.Attribute("id") == configurationID)
                                .Elements("add");

                        if (targetElements != null)
                        {
                            XElement targetElement = targetElements.FirstOrDefault();
                            if (targetElement != null)
                            {
                                XAttribute targetAttribute = targetElement.Attribute("value");
                                if (targetAttribute != null)
                                {
                                    targetAttribute.SetValue(referenceAttribute.Value);
                                }
                            }
                        }
                    }
                }

                _compositionCache.Add(configurationID);

                return true;
            }
            catch (Exception exception)
            {
                Trace.WriteLine(string.Format("Exception: {0}", exception), "DomainComposer.PerformComposition");
                throw;
            }
        }

        #endregion
    }
}